//
//  ClosureExample.swift
//  SwiftTest
//
//  Created by bym on 2019/8/6.
//  Copyright © 2019 ZZ. All rights reserved.
//

import UIKit

class ClosureExample: NSObject {
	override init() {
		super.init()
		//做参数
		closureAsParam {
			ZZLogFunc()
		}
		//做返回值
		let derivedClosure = closureAsReturn()
		derivedClosure()
		
		//柯里化
		let add2 = addTo(2)
		var i = 0
		i = add2(i)
		ZZLog(i)
		i = add2(i)
		ZZLog(i)
		
		let add3 = addTo(3)
		i = add3(i)
		ZZLog(i)
		i = add3(i)
		ZZLog(i)
	}
}

///闭包作为参数
extension ClosureExample{
	func closureAsParam(_ param:()->()){
		param()
	}
}

///闭包作为返回值
extension ClosureExample {
	func closureAsReturn()->()->() {
		return {
			ZZLogFunc()
		}
	}
	
	///王巍 swift的100个tips
	///tip1 柯里化 创建方法的方法
	///说白了就是返回值是闭包的函数
	func addTo(_ addNum:Int) -> (_ baseNum:Int) -> Int{
		return{
			$0 + addNum
		}
	}
	
	
}

///捕获
extension ClosureExample{
	func capture(){
		//eg.: 1
		var counter = 0
		let incrementCounter = {
			counter += 1
		}
		
		/*
		由于闭包定义和变量counter在同一作用域中，
		故闭包可以捕获并访问变量counter。
		对变量counter做的任何改变，对闭包来说都是透明可见的。
		*/
		
		incrementCounter() //1
		incrementCounter() //2
		
		//eg.: 2
		func countingClosure() -> () -> Int {
			var counter = 0
			let incrementCounter: () -> Int = {
				counter += 1
				return counter
			}
			return incrementCounter
		}
		
		/*
		该例子中，闭包捕获了封闭空间（函数实体内）的内部变量counter。
		*/
		let counter1 = countingClosure()
		let counter2 = countingClosure()
		
		counter1() // 1
		counter2() // 1
		counter1() // 2
		counter1() // 3
		counter2() // 2
	}
}

///闭包语法
extension ClosureExample{
	func closureSyntax() {
		/*
		无名
		本质是函数
		使用时注意循环引用
		闭包是无名的，因为他们能够从上下文中捕获变量、常量，从而应用在自身的作用区域。
		*/
		//声明
		//注意 () -> String 实际上是一个无名函数，作为闭包变量的类型。
		var myClosure: () -> String
		
		//无返回值的闭包
		let myClosure1:() -> Void = {[weak self] in
			guard let strongSelf = self else {
				return
			}
			print("Hello world")
			
		}
		//执行闭包
		myClosure1()
		
		
		//尝试一个带参的闭包
		var mySecondClosure: (Int , Int ) -> Int = {
			(a: Int , b: Int) -> Int in
			return a * b
		}
		
		//第一次简化 类型自动推导 可以根据参数推断
		var mySecondClosure1 : (Int , Int ) -> Int = {
			(a, b) in
			return a * b
		}
		
		//第二次简化 如果函数体只包含一句 return 代码，可省略 return
		var mySecondClosure2 : (Int , Int ) -> Int = {
			(a, b) in
			a * b
		}
		
		/*
		第三次简化
		被捕获的参数列表中，含有a、b，下标从0开始，可通过"$"获取。
		
		编译器亦可通过，捕获列表自行推断出参数。
		故可省略参数列表 （a, b）和 关键字 in
		*/
		var mySecondClosure3 : (Int , Int ) -> Int = {
			$0 * $1
		}
	}
}


